<template>
  <a-modal
    class="image-cropper"
    v-model:open="visible"
    title="编辑图片"
    :footer="false"
    @cancel="closeModal"
  >
    <!-- 图片裁切组件 -->
    <vue-cropper
      ref="cropperRef"
      :img="imageUrl"
      output-type="png"
      :info="true"
      :can-move-box="true"
      :fixed-box="false"
      :auto-crop="true"
      :center-box="true"
    />
    <div style="margin-bottom: 16px" />
    <a-button v-if="canEnterEdit" type="primary" @click="enterEdit">进入编辑</a-button>
    <a-button v-if="canExitEdit" type="primary" @click="exitEdit">退出编辑</a-button>
    <div style="margin-bottom: 16px" />
    <!-- 图片操作 -->
    <div class="image-cropper-actions">
      <a-space>
        <a-button @click="rotateLeft" :disabled="!canEdit">向左旋转</a-button>
        <a-button @click="rotateRight" :disabled="!canEdit">向右旋转</a-button>
        <a-button @click="changeScale(1)" :disabled="!canEdit">放大</a-button>
        <a-button @click="changeScale(-1)" :disabled="!canEdit">缩小</a-button>
        <a-button type="primary" :loading="loading" @click="handleConfirm" :disabled="!canEdit"
          >确认</a-button
        >
      </a-space>
    </div>
  </a-modal>
</template>

<script lang="ts" setup>
import { ref, computed, watchEffect, onUnmounted } from 'vue'
import { uploadPictureUsingPost } from '@/api/pictureController.ts'
import { message } from 'ant-design-vue'
import { useLoginUserStore } from '@/stores/useLoginUserStore'
import PictureEditWebSocket from '@/utils/PictureEditWebSocket'
import { PICTURE_EDIT_MESSAGE_TYPE_ENUM, PICTURE_EDIT_ACTION_ENUM } from '@/constants/pictureEnum'

interface Props {
  imageUrl?: string
  picture?: API.PictureVO
  onSuccess?: (newPicture: API.PictureVO) => void
}

const props = defineProps<Props>()

// 获取图片裁切器的引用
const cropperRef = ref()

// 确认裁切
const handleConfirm = () => {
  cropperRef.value.getCropBlob((blob: Blob) => {
    // blob 为已经裁切好的文件
    const fileName = (props.picture?.name || 'image') + '.png'
    const file = new File([blob], fileName, { type: blob.type })
    // 上传图片
    handleUpload({ file })
  })
}

const loading = ref(false)

/**
 * 上传图片
 * @param file
 */
const handleUpload = async ({ file }: { file: File }) => {
  loading.value = true
  try {
    const params: API.PictureUploadRequest = props.picture
      ? { id: props.picture.id, pictureName: props.picture.name }
      : {}
    params.spaceId = props.picture?.spaceId
    const response = (await uploadPictureUsingPost(params, {}, file)) as {
      data?: { code: number; data: API.PictureVO; message: string }
    }
    if (response.data?.code === 200 && response.data?.data) {
      message.success('图片上传成功')
      props.onSuccess?.(response.data.data)
      closeModal()
    } else {
      message.error('图片上传失败，' + (response.data?.message || '未知错误'))
    }
  } catch (error) {
    console.error('图片上传失败', error)
    message.error('图片上传失败，' + (error instanceof Error ? error.message : '发生未知错误'))
  }
  loading.value = false
}

// 向左旋转
const rotateLeft = () => {
  cropperRef.value.rotateLeft()
  editAction(PICTURE_EDIT_ACTION_ENUM.ROTATE_LEFT)
}

// 向右旋转
const rotateRight = () => {
  cropperRef.value.rotateRight()
  editAction(PICTURE_EDIT_ACTION_ENUM.ROTATE_RIGHT)
}

// 缩放比例
const changeScale = (num: number) => {
  cropperRef.value.changeScale(num)
  editAction(num > 0 ? PICTURE_EDIT_ACTION_ENUM.ZOOM_IN : PICTURE_EDIT_ACTION_ENUM.ZOOM_OUT)
}

// 是否可见
const visible = ref(false)

// 打开弹窗
const openModal = () => {
  visible.value = true
}

// 关闭弹窗
const closeModal = () => {
  visible.value = false
  if (pictureEditWebSocket) {
    pictureEditWebSocket.disconnect()
  }
  editingUser.value = undefined
}

// ------实时编辑------
const loginUserStore = useLoginUserStore()
const loginUserInfo = loginUserStore.loginUserInfo
// 正在编辑用户
const editingUser = ref<API.UserVO>()
const canEnterEdit = computed(() => {
  return !editingUser.value
})
// 可以退出编辑
const canExitEdit = computed(() => {
  return editingUser.value?.id === loginUserInfo?.userId
})
// 可以编辑
const canEdit = computed(() => {
  return editingUser.value?.id === loginUserInfo?.userId
})

let pictureEditWebSocket: PictureEditWebSocket | null

const initWebSocket = () => {
  const pictureId = props.picture?.id
  if (!pictureId || !visible.value) {
    return
  }
  pictureEditWebSocket = new PictureEditWebSocket(pictureId)
  pictureEditWebSocket.connect()

  pictureEditWebSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.INFO, (msg) => {
    // console.log('msg', msg)
    message.info(msg.message)
  })
  pictureEditWebSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.ERROR, (msg) => {
    message.error(msg.message)
  })
  pictureEditWebSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.ENTER_EDIT, (msg) => {
    // console.log('msg', msg)
    message.info(msg.message)
    editingUser.value = msg.user
  })
  pictureEditWebSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.EDIT_ACTION, (msg) => {
    // console.log('msg', msg)
    message.info(msg.message)
    // editingUser.value = msg.user
    switch (msg.editAction) {
      case PICTURE_EDIT_ACTION_ENUM.ROTATE_LEFT:
        rotateLeft()
        break
      case PICTURE_EDIT_ACTION_ENUM.ROTATE_RIGHT:
        rotateRight()
        break
      case PICTURE_EDIT_ACTION_ENUM.ZOOM_IN:
        changeScale(1)
        break
      case PICTURE_EDIT_ACTION_ENUM.ZOOM_OUT:
        changeScale(-1)
        break
    }
  })
  pictureEditWebSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.EXIT_EDIT, (msg) => {
    // console.log('msg', msg)
    message.info(msg.message)
    editingUser.value = undefined
  })
}
// 监听弹窗是否打开
watchEffect(() => {
  if (visible.value) {
    initWebSocket()
  } else {
    pictureEditWebSocket?.disconnect()
  }
})
onUnmounted(() => {
  if (pictureEditWebSocket) {
    pictureEditWebSocket.disconnect()
  }
  editingUser.value = undefined
})

const enterEdit = () => {
  if (pictureEditWebSocket) {
    pictureEditWebSocket.sendMessage({
      type: PICTURE_EDIT_MESSAGE_TYPE_ENUM.ENTER_EDIT,
    })
  }
}

const editAction = (action: string) => {
  if (pictureEditWebSocket) {
    pictureEditWebSocket.sendMessage({
      type: PICTURE_EDIT_MESSAGE_TYPE_ENUM.EDIT_ACTION,
      editAction: action,
    })
  }
}

const exitEdit = () => {
  if (pictureEditWebSocket) {
    pictureEditWebSocket.sendMessage({
      type: PICTURE_EDIT_MESSAGE_TYPE_ENUM.EXIT_EDIT,
    })
  }
}

// 暴露函数给父组件
defineExpose({
  openModal,
})
</script>

<style>
.image-cropper {
  text-align: center;
}

.image-cropper .vue-cropper {
  height: 400px !important;
}
</style>
